#include "Python.h"
#include "structmember.h"

#include <windows.h>


static int ThreadID;

PyDoc_STRVAR(event_doc,
"event module\n");

typedef struct {
	PyObject_HEAD
	int		exitcode;
	int		shouldexit;
} EventLoopObject;

PyDoc_STRVAR(eventloop_doc,
"Event Loop Object\n");

static PyObject *
EventLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	EventLoopObject		*self;

	self = (EventLoopObject *)type->tp_alloc(type, 0);
	if (self != NULL) {
		self->exitcode = 0;
		self->shouldexit = 0;
	}

	return (PyObject *)self;
}

static int *
EventLoop_init(EventLoopObject *self, PyObject *args, PyObject *kwds)
{
	return 0;
}

/* Process a single message */
static void
ProcessMessage(void *msg)
{
	TranslateMessage(msg);
	DispatchMessage(msg);
}

PyDoc_STRVAR(eventloop_dispatch_doc,
"dispatch a single event, return false if we should exit from the loop\n");

static PyObject *
eventloop_dispatch(PyObject *self)
{
	MSG		msg;
	int		ret;

	printf("befor get message \n");
	Py_BEGIN_ALLOW_THREADS;
	ret = GetMessage(&msg, (HWND)NULL, 0, 0);
	Py_END_ALLOW_THREADS;
	printf("after get message\n");

	if (ret == 0)
		;
		/* Got WM_QUIT Message */
		//Py_RETURN_FALSE;
	

	if (ret == -1) {
		PyErr_SetString(PyExc_RuntimeError, 
				"Call GetMessage Error at eventloop.dispatch");
		return NULL;
	}

	ProcessMessage(&msg);
	Py_RETURN_TRUE;
}

PyDoc_STRVAR(eventloop_wakeup_doc,
"Wake up the loop: post a dummy event to the loop\n");

static PyObject *
eventloop_wakeup(PyObject *self)
{
	printf("befor post message\n");
	PostThreadMessage(ThreadID, WM_NULL, 0, 0);
	printf("after post message\n");
	Py_RETURN_NONE;
}

PyDoc_STRVAR(eventloop_exit_doc,
"exit from the loop with the given exit code\n");

static PyObject *
eventloop_exit(PyObject *self, PyObject *args)
{
	EventLoopObject *me = (EventLoopObject *)self;
	int exitcode = 0;

	printf("exit\n");
	if (!PyArg_ParseTuple(args, "|i", &exitcode))
		return NULL;

	me->exitcode = exitcode;
	me->shouldexit = 1;

	printf("exit\n");
	eventloop_wakeup(self);
	printf("exit\n");

	Py_RETURN_NONE;
}

PyDoc_STRVAR(eventloop_pending_doc,
"return true if any events are available\n");

static PyObject *
eventloop_pending(PyObject *self)
{
	MSG		msg;
	if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0)
		Py_RETURN_TRUE;
	else
		Py_RETURN_FALSE;
}

PyDoc_STRVAR(eventloop_run_doc,
"start the event loop, return the exit code\n");

static PyObject *
eventloop_run(PyObject *self)
{
	EventLoopObject	*me = (EventLoopObject *)self;
	ThreadID = GetCurrentThreadId();

	while (1) {
		printf("loop once\n");
		//while (eventloop_pending(self) == Py_False)
			;
		printf("loop once %d\n", me->shouldexit);

		if (me->shouldexit) {
		printf("loop once\n");
			while (eventloop_pending(self) == Py_True)
				eventloop_dispatch(self);
		printf("loop once\n");
			break;
		}
		printf("loop once\n");

		if (eventloop_dispatch(self) == Py_False)
			/* Got WM_QUIT Message */
			break;

	}

	return PyLong_FromLong(me->exitcode);
}


static struct PyMemberDef eventloop_members[] = {
	{"exitcode", T_INT, offsetof(EventLoopObject, exitcode), 0, 
		"exit code"},
	{"shouldexit", T_INT, offsetof(EventLoopObject, shouldexit), 0, 
		"tell if should exit now"},
	{NULL}
};

static struct PyMethodDef eventloop_methods[] = {
	{"dispatch", (PyCFunction)eventloop_dispatch, METH_NOARGS,
		eventloop_dispatch_doc},
	{"exit", (PyCFunction)eventloop_exit, METH_VARARGS,
		eventloop_exit_doc},
	{"pending", (PyCFunction)eventloop_pending, METH_NOARGS,
		eventloop_pending_doc},
	{"run", (PyCFunction)eventloop_run, METH_NOARGS,
		eventloop_run_doc},
	{"wakeup", (PyCFunction)eventloop_wakeup, METH_NOARGS,
		eventloop_wakeup_doc},
	{NULL, NULL}
};

static void
eventloop_dealloc(PyObject *ob)
{
}

static PyTypeObject PyEventLoop_Type = {
	PyObject_HEAD_INIT(0)
        "event.EventLoop",		/* tp_name */
        sizeof(EventLoopObject),		/* tp_basicsize */
        0,				/* tp_itemsize */
        eventloop_dealloc,		/* tp_dealloc */
        0,				/* tp_print */
        0,				/* tp_getattr */
        0,				/* tp_setattr */
        0,				/* tp_reserved */
        0,				/* tp_repr */
        0,				/* tp_as_number */
        0,				/* tp_as_sequence */
        0,				/* tp_as_mapping */
        0,				/* tp_hash */
        0,				/* tp_call */
        0,				/* tp_str */
        PyObject_GenericGetAttr,	/* tp_getattro */
        0,				/* tp_setattro */
        0,				/* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,		/* tp_flags */
        eventloop_doc,		/* tp_doc */
        0,				/* tp_traverse */
        0,				/* tp_clear */
        0,				/* tp_richcompare */
        0,				/* tp_weaklistoffset */
        0,				/* tp_iter */
        0,				/* tp_iternext */
        eventloop_methods,		/* tp_methods */
        eventloop_members,				/* tp_members */
        0,				/* tp_getset */
        0,				/* tp_base */
        0,				/* tp_dict */
        0,				/* tp_descr_get */
        0,				/* tp_descr_set */
        0,				/* tp_dictoffset */
        (initproc)EventLoop_init,				/* tp_init */
        0,				/* tp_alloc */
        EventLoop_new,				/* tp_new */
        0,				/* tp_free */
        0,				/* tp_is_gc */
};

static PyObject *
event_test(PyObject *o)
{
	Py_RETURN_NONE;
}

static PyMethodDef eventmethods[] = {
	{"test", (PyCFunction)event_test, METH_NOARGS,
		"test method for some covenience"},
	{NULL, NULL, 0, NULL}
};

static EventLoopObject *active_loop = NULL;

static PyModuleDef eventmodule = {
	PyModuleDef_HEAD_INIT,
	"event",
	event_doc,
	-1,
	eventmethods
};

PyMODINIT_FUNC
PyInit_event(void)
{
	PyObject *m;

	if (PyType_Ready(&PyEventLoop_Type) < 0)
		return NULL;

	m = PyModule_Create(&eventmodule);
	if (m == NULL)
		return NULL;

	Py_INCREF(&PyEventLoop_Type);
	PyModule_AddObject(m, "EventLoop", (PyObject *)&PyEventLoop_Type);

	active_loop = (EventLoopObject *)Py_None;
	Py_INCREF(active_loop);
	PyModule_AddObject(m, "active_loop", (PyObject *)active_loop);
	return m;
}
